//  Model.hpp
//  PureMVC_C++
//
//  PureMVC Port to C++ by Tang Khai Phuong <phuong.tang@puremvc.org>
//  PureMVC - Copyright(c) 2006-2011 Futurescale, Inc., Some rights reserved.
//  Your reuse is governed by the Creative Commons Attribution 3.0 License
//
//  中文注释：
//  Model类是PureMVC框架中的核心组件之一，实现了IModel接口。
//  它负责管理应用程序的数据模型，通过Proxy对象来维护数据。
//  Model采用Multiton模式实现，确保每个键对应唯一的实例。
//

#if !defined(__PUREMVC_CORE_MODEL_HPP__)
#define __PUREMVC_CORE_MODEL_HPP__

// STL include
#include <string>
#include <exception>
#include <stdexcept>
#include <cassert>
// PureMVC include
#if !defined(__PUREMVC_HPP__)
#define __PUREMVC_INCLUDE__
#include "../PureMVC.hpp"
#endif /* __PUREMVC_HPP__ */
#if defined(PUREMVC_USES_TR1)
#if defined(__GNUC__) || defined(__MINGW32__)
#include <tr1/unordered_map>
#else
#include <unordered_map>
#endif
#else
#include <map>
#endif

#include "../Interfaces/IModel.hpp"
#include "../Interfaces/IProxy.hpp"
#include "../Patterns/Iterator/Iterator.hpp"

namespace PureMVC
{
    namespace Core
    {
        using Interfaces::IModel;
        using Interfaces::IProxy;
        using Interfaces::IAggregate;
        using Interfaces::IIterator;

        /**
         * A Multiton <code>IModel</code> implementation.
         *
         * <P>
         * In PureMVC, the <code>Model</code> class provides
         * access to model objects (Proxies) by named lookup.
         *
         * <P>
         * The <code>Model</code> assumes these responsibilities:</P>
         *
         * <UL>
         * <LI>Maintain a cache of <code>IProxy</code> instances.</LI>
         * <LI>Provide methods for registering, retrieving, and removing
         * <code>IProxy</code> instances.</LI>
         * </UL>
         *
         * <P>
         * Your application must register <code>IProxy</code> instances
         * with the <code>Model</code>. Typically, you use an
         * <code>ICommand</code> to create and register <code>IProxy</code>
         * instances once the <code>Facade</code> has initialized the Core
         * actors.</p>
         *
         * @see Patterns/Proxy/Proxy.hpp PureMVC::Patterns::Proxy
         * @see Interfaces/IProxy.hpp PureMVC::Interfaces::IProxy
         *
         * 中文注释：
         * Model类是IModel接口的Multiton实现。
         *
         * 在PureMVC中，Model类通过名称查找提供对模型对象（Proxy）的访问。
         *
         * Model承担以下责任：
         * 1. 维护IProxy实例的缓存
         * 2. 提供注册、检索和删除IProxy实例的方法
         *
         * 应用程序必须向Model注册IProxy实例。通常，在Facade初始化核心组件后，
         * 您可以使用ICommand来创建和注册IProxy实例。
         */
        class PUREMVC_API Model : public virtual IModel
        {
        protected:
#if defined(PUREMVC_USES_TR1)
            typedef std::tr1::unordered_map<std::string, IProxy*> ProxyMap;
#else
            typedef std::map<std::string, IProxy*> ProxyMap;
#endif
        protected:
            /**
             * 定义迭代器转换器，仅用于获取代理名称
             * Define iterator converter for getting proxy name only.
             */
            struct IteratorConverter
#if !defined(__DMC__) // The C++ compiler of Digital Mars cannot resolve this case
                : public std::unary_function<ProxyMap::const_iterator, ProxyMap::key_type> 
#endif          
            {
                /**
                 * 转换操作符
                 * Converting operator.
                 *
                 * @param iterator 内部容器的迭代器
                 * @param iterator the iterator of internal container.
                 * @return 迭代器中代理的名称
                 * @return the name of proxy inside iterator.
                 */
                ProxyMap::key_type const& operator()(ProxyMap::const_iterator const& iterator) const;
            };
            /**
             * 定义内部容器的迭代器范围
             * Define iterator range of internal container.
             */
            struct IteratorRange {
                /**
                 * 获取起始点
                 * Get begin point.
                 *
                 * @return 迭代器的起始位置
                 * @return the begin of iterator.
                 */
                ProxyMap::const_iterator begin(ProxyMap const* const& iterator) const;
                /**
                 * 获取结束点
                 * Get end point.
                 *
                 * @return 迭代器的结束位置
                 * @return the end of iterator.
                 */
                ProxyMap::const_iterator end(ProxyMap const* const& iterator) const;
            };
        public:
            /** 默认的Multiton键 */
            static char const* const DEFAULT_KEY;
        protected:
            // 消息常量
            /** 当尝试创建重复的Multiton实例时抛出的错误消息 */
            static char const* const MULTITON_MSG;
            // 此核心的Multiton键
            /** 用于标识Model实例的Multiton键 */
            std::string const _multiton_key;
            // proxy名称到IProxy实例的映射
            /** 存储所有注册的Proxy实例的映射表 */
            ProxyMap _proxy_map;
            // 同步访问
            /** 用于确保线程安全的互斥锁 */
            mutable FastMutex _synchronous_access;
        private:
            /** 禁止拷贝构造函数 */
            Model(Model const&);
            /** 禁止从IModel接口拷贝构造 */
            Model(IModel const&);
            /** 禁止赋值操作符 */
            Model& operator=(Model const&);
            /** 禁止从IModel接口赋值 */
            Model& operator=(IModel const&);
        protected:
            /**
             * 根据键查找Model实例
             * @param key 要查找的Multiton键
             * @return 找到的Model实例，如果不存在则返回nullptr
             */
            static IModel* find(std::string const& key);
            /**
             * 插入一个Model实例到Multiton映射中
             * @param key 要插入的Multiton键
             * @param model 要插入的Model实例
             */
            static void insert(std::string const& key, IModel* model);
        public:
            /**
             * 构造函数
             * Constructor.
             *
             * <P>
             * 此<code>IModel</code>实现是一个Multiton，
             * 因此不应直接调用构造函数，而应调用静态Multiton工厂方法
             * <code>Model.getInstance( multitonKey )</code>
             * This <code>IModel</code> implementation is a Multiton,
             * so you should not call the constructor
             * directly, but instead call the static Multiton
             * Factory method <code>Model.getInstance( multitonKey )</code>
             *
             * @throws Error 如果已为此Multiton键构造了实例，则抛出错误
             * @throws Error Error if instance for this Multiton key instance has already been constructed
             *
             * @param key 可选的Multiton键，默认为DEFAULT_KEY
             */
            explicit Model(std::string const& key = PureMVC::Core::Model::DEFAULT_KEY);

        protected:
            /**
             * 构造函数（模板版本）
             * Constructor.
             *
             * <P>
             * 支持在基类（<code>Model</code>）的构造函数中调用虚方法。
             * Support call virtual method in constructor of base class (<code>Model</code>).
             *
             * 条件：派生类（继承自<code>Model</code>的类）必须实现initializeModel方法
             * Condition: Derived class (class inherit from <code>Model</code>) must implement method: initializeModel
             *
             * 请使用以下方式：
             * Please use this way:
             * <code>
             * 
             * ConcreateModel::ConcreateModel(void)
             * :Model(this)
             * {
             *     // 你的代码在这里
             *     // Your code here
             * }
             * </code>
             *
             * 工厂方法 <code>Model::getInstance( key )</code>
             * Factory method <code>Model::getInstance( key )</code>
             *
             * @throws Error 如果已为此Multiton键构造了实例，则抛出错误
             * @throws Error Error if instance for this Multiton key has already been constructed
             *
             * @param instance 派生类实例的指针
             * @param key 可选的Multiton键，默认为DEFAULT_KEY
             */
            template<typename _DerivedType>
            explicit Model(_DerivedType* instance, std::string const& key = PureMVC::Core::Model::DEFAULT_KEY)
                : _multiton_key(key)
            {
                if (find(key))
                    throw std::runtime_error(MULTITON_MSG);
                insert(_multiton_key, this);
                instance->_DerivedType::initializeModel();
            }

            /**
             * 初始化<code>Model</code>实例
             * Initialize the <code>Model</code> instance.
             *
             * <P>
             * 由构造函数自动调用，这是在子类中初始化单例实例
             * 而不重写构造函数的机会。
             * Called automatically by the constructor, this
             * is your opportunity to initialize the Singleton
             * instance in your subclass without overriding the
             * constructor.</P>
             *
             * @return void
             */
            virtual void initializeModel(void);

        public:
            /**
             * <code>Model</code> Multiton工厂方法
             * <code>Model</code> Multiton Factory method.
             *
             * @param key 可选的Multiton键，默认为DEFAULT_KEY
             * @return 此Multiton键对应的实例
             * @return the instance for this Multiton key
             */
            static IModel& getInstance(std::string const& key = PureMVC::Core::Model::DEFAULT_KEY);

            /**
             * 向<code>Model</code>注册一个<code>IProxy</code>
             * Register an <code>IProxy</code> with the <code>Model</code>.
             *
             * @param proxy 要由<code>Model</code>持有的<code>IProxy</code>实例
             * @param proxy an <code>IProxy</code> to be held by the <code>Model</code>.
             */
            virtual void registerProxy(IProxy* proxy);

            /**
             * 从<code>Model</code>中检索一个<code>IProxy</code>（常量版本）
             * Retrieve an <code>IProxy</code> from the <code>Model</code>.
             *
             * @param proxy_name 要检索的Proxy名称
             * @param proxy_name
             * @return 先前用给定<code>proxyName</code>注册的<code>IProxy</code>实例
             * @return the <code>IProxy</code> instance previously registered with the given <code>proxyName</code>.
             */
            virtual IProxy const& retrieveProxy(std::string const& proxy_name) const;

            /**
             * 从<code>Model</code>中检索一个<code>IProxy</code>（非常量版本）
             * Retrieve an <code>IProxy</code> from the <code>Model</code>.
             *
             * @param proxy_name 要检索的Proxy名称
             * @param proxy_name
             * @return 先前用给定<code>proxyName</code>注册的<code>IProxy</code>实例
             * @return the <code>IProxy</code> instance previously registered with the given <code>proxyName</code>.
             */
            virtual IProxy& retrieveProxy(std::string const& proxy_name);

            /**
             * 检查是否注册了指定的Proxy
             * Check if a Proxy is registered
             *
             * @param proxy_name 要检查的Proxy名称
             * @param proxy_name
             * @return 当前是否用给定的<code>proxyName</code>注册了Proxy
             * @return whether a Proxy is currently registered with the given <code>proxyName</code>.
             */
            virtual bool hasProxy(std::string const& proxy_name) const;

            /**
             * 从<code>Model</code>中移除一个<code>IProxy</code>
             * Remove an <code>IProxy</code> from the <code>Model</code>.
             *
             * @param proxy_name 要移除的<code>IProxy</code>实例的名称
             * @param proxy_name name of the <code>IProxy</code> instance to be removed.
             * @return 从<code>Model</code>中移除的<code>IProxy</code>
             * @return the <code>IProxy</code> that was removed from the <code>Model</code>
             */
            virtual IProxy* removeProxy(std::string const& proxy_name);

            /**
             * 列出所有代理的名称
             * List all names of proxy
             *
             * @return <code>proxy_name</code>的聚合容器
             * @return the aggregate container of <code>proxy_name</code>.
             */
            virtual ProxyNames listProxyNames(void) const;

            /**
             * 移除一个IModel实例
             * Remove an IModel instance
             *
             * @param key 要移除的IModel实例的键
             * @param key of IModel instance to remove
             */
            static void removeModel(std::string const& key);
            
            /**
             * 虚析构函数
             * Virtual destructor.
             */
            virtual ~Model(void);
        };
    }
}

#endif /* __PUREMVC_CORE_MODEL_HPP__ */
